package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"net/http"
	"os/exec"
	"strconv"
	"time"
)

func main() {
	http.HandleFunc("/giteewebhooks", httpHandle)
	err := http.ListenAndServe(":"+strconv.Itoa(httpPort), nil)
	if err != nil {
		println(time.Now().Format("2006-01-02 15:04:05"), 0, "http.ListenAndServe", err.Error())
	}
}

var (
	gitPath  = "/www/wwwroot/www.mmwyx.com"
	response = map[string]any{
		"status": false,
		"code":   0,
		"msg":    "失败",
	}
	httpPort = 9877
)

func httpHandle(w http.ResponseWriter, r *http.Request) {

	if r.Method != "POST" {
		return
	}

	if r.Header.Get("Content-Type") != "application/json" {
		response["status"] = false
		response["code"] = 1
		response["msg"] = "content-type错误"
		jsonStr, err := json.Marshal(response)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 1, "json.Marshal", err.Error())
			return
		}
		_, err = w.Write(jsonStr)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 2, "w.Write", err.Error())
		}
		return
	}

	if r.Header.Get("User-Agent") != "git-oschina-hook" {
		response["status"] = false
		response["code"] = 2
		response["msg"] = "user-agent错误"
		jsonStr, err := json.Marshal(response)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 3, "json.Marshal", err.Error())
			return
		}
		_, err = w.Write(jsonStr)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 4, "w.Write", err.Error())
		}
		return
	}

	timestampStr := r.Header.Get("X-Gitee-Timestamp")
	timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
	if err != nil {
		response["status"] = false
		response["code"] = 3
		response["msg"] = "x-gitee-timestamp解析错误"
		jsonStr, err := json.Marshal(response)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 5, "json.Marshal", err.Error())
			return
		}
		_, err = w.Write(jsonStr)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 6, "w.Write", err.Error())
		}
		return
	}

	if abs(time.Now().UnixMilli()-timestamp) > 3600000 {
		response["status"] = false
		response["code"] = 4
		response["msg"] = "x-gitee-timestamp错误"
		jsonStr, err := json.Marshal(response)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 7, "json.Marshal", err.Error())
			return
		}
		_, err = w.Write(jsonStr)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 8, "w.Write", err.Error())
		}
		return
	}

	if r.Header.Get("X-Gitee-Event") == "" {
		response["status"] = false
		response["code"] = 5
		response["msg"] = "x-gitee-event错误"
		jsonStr, err := json.Marshal(response)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 9, "json.Marshal", err.Error())
			return
		}
		_, err = w.Write(jsonStr)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 10, "w.Write", err.Error())
		}
		return
	}

	if r.Header.Get("X-Gitee-Token") == "" {
		response["status"] = false
		response["code"] = 6
		response["msg"] = "x-gitee-token错误"
		jsonStr, err := json.Marshal(response)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 11, "json.Marshal", err.Error())
			return
		}
		_, err = w.Write(jsonStr)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 12, "w.Write", err.Error())
		}
		return
	}

	secret := "12332112345677887921"
	signData := generateSignData(timestampStr, secret)

	if signData != r.Header.Get("X-Gitee-Token") {
		response["status"] = false
		response["code"] = 7
		response["msg"] = "x-gitee-token错误"
		jsonStr, err := json.Marshal(response)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 13, "json.Marshal", err.Error())
			return
		}
		_, err = w.Write(jsonStr)
		if err != nil {
			println(time.Now().Format("2006-01-02 15:04:05"), 14, "w.Write", err.Error())
		}
		return
	}

	go executeGitPull()

	response["status"] = true
	response["code"] = 0
	response["msg"] = "成功"
	jsonStr, err := json.Marshal(response)
	if err != nil {
		println(time.Now().Format("2006-01-02 15:04:05"), 15, "json.Marshal", err.Error())
		return
	}
	_, err = w.Write(jsonStr)
	if err != nil {
		println(time.Now().Format("2006-01-02 15:04:05"), 16, "w.Write", err.Error())
	}
}

func generateSignData(timestamp string, secret string) string {
	message := timestamp + "\n" + secret
	hash := hmac.New(sha256.New, []byte(secret))
	hash.Write([]byte(message))
	signBytes := hash.Sum(nil)
	return base64.StdEncoding.EncodeToString(signBytes)
}

func abs(x int64) int64 {
	if x < 0 {
		return -x
	}
	return x
}

func executeGitPull() {
	cmd := exec.Command("git", "pull")
	cmd.Dir = gitPath
	output, err := cmd.CombinedOutput()
	if err != nil {
		println(time.Now().Format("2006-01-02 15:04:05"), 17, "exec.Command", err.Error())
		return
	}
	println(time.Now().Format("2006-01-02 15:04:05"), 18, "success", string(output))
}
